# _*_ coding:utf-8 _*_
# @Time  : 2023.08.25
# @Author: zizlee
import json
import math
import pathlib
import datetime
from fastapi import APIRouter, HTTPException, Query
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle

from utils import datetime_utils
from response import APIResponse
from settings import FILE_STORAGE, STATIC_HOST
from .doctor_tools import report_temp_files, MixAppraise, ExDoctorDatabase, FundReconciler, CloseStatistician, SyntheticalAppraise


class PdfGenerator(object):
    TEMP_FOLDER = pathlib.Path(FILE_STORAGE, 'sysTemp/exDoctor')
    PDF_TEMP_FOLDER = pathlib.Path(FILE_STORAGE, 'sysTemp/exDoctor/pdfReport')

    def __init__(self, filename_prefix, start_date: datetime.date, end_date: datetime.date, net_value=0,
                 page_sizes=A4, close_count=0):  # close_count平仓笔数 net_value累计净值
        self.start_date = start_date
        self.end_date = end_date
        self.net_value = net_value
        self.PAGE_WIDTH, self.PAGE_HEIGHT = page_sizes
        self.filename_prefix = filename_prefix
        self.pdf_simple_styles = getSampleStyleSheet()
        self.pdf_simple_styles.add(ParagraphStyle(fontName='SyH_N', name='Song'))
        self.pdf_simple_styles.add(ParagraphStyle(fontName='SyH_B', name='SongBD'))
        # print('PDF页面大小:', self.PAGE_WIDTH, self.PAGE_HEIGHT)
        self.pdf_folder = self.PDF_TEMP_FOLDER.joinpath(f'{datetime.datetime.now().strftime("%Y%m%d")}')
        if not self.pdf_folder.exists():
            self.pdf_folder.mkdir(parents=True)
        folder = str(self.pdf_folder).replace("\\", "/")
        self.pdf_filepath = f'{folder}/{filename_prefix}_交易诊断报告({self.start_date.strftime("%Y%m%d")}至{self.end_date.strftime("%Y%m%d")}).pdf'
        self.close_count = close_count
        # print(self.PAGE_HEIGHT, 2 * inch, self.PAGE_HEIGHT - 2 * inch - 15)
        self.story = []

    def create_blank_file(self):  # 无数据文件
        doc = SimpleDocTemplate(self.pdf_filepath)  # 默认页边距=inch
        # 第一页空白不知道为啥还要-15，可能布局的问题吧，因为用showPage()页码会不对
        self.story.append(Spacer(1, self.PAGE_HEIGHT - 2 * inch - 15))
        self.story.append(Spacer(1, 3 * inch))
        self.add_paragraph(text='本系统暂无查询期间的交易数据，您可以选择更早的日期区间进行分析.', font_name='SyH_B', name='SongBD', font_size=20, alignment=TA_CENTER, leading=30)
        self.story.append(Spacer(1, 2 * inch))
        self.add_paragraph(text='谢谢使用', font_name='SyH_B', name='SongBD', font_size=32, alignment=TA_CENTER)
        doc.build(self.story, onFirstPage=self.first_page_event, onLaterPages=self.later_page_event)
        return self.pdf_filepath.replace('\\', '/').replace(FILE_STORAGE, '')

    def create_pdf_file(self):
        doc = SimpleDocTemplate(self.pdf_filepath)  # 默认页边距=inch
        # 第一页空白不知道为啥还要-15，可能布局的问题吧，因为用showPage()页码会不对
        self.story.append(Spacer(1, self.PAGE_HEIGHT - 2 * inch - 15))
        # 文档标题(使用封面)
        # self.add_paragraph(text='交易诊断报告', font_name='SyH_B', name='SongBD', alignment=TA_CENTER,
        #                    font_size=20, auto_space=(1, 0.5 * inch))
        # 特别提示
        self.add_paragraph(text='特别提示', font_name='SyH_B', name='SongBD', alignment=TA_CENTER,
                           font_size=18, auto_space=(1, 0.5 * inch))

        self.add_paragraph(text='1. 根据账号情况，诊断报告最长可查询2年时间交易情况，最短5个交易日。', leading=16, auto_space=(1, 0.06 * inch))
        self.add_paragraph(text='2. 报告数据只根据期货方面的交易记录来统计分析，不包含期权在内。', leading=16, auto_space=(1, 0.06 * inch))
        self.add_paragraph(text='3. 报告为过往交易数据分析所得，所展示的信息内容仅作为参考，不能作为具体的投资依据，您不应单纯依靠本产品而取代个人的独立判断，应根据当前市场做出投资决策。',
                           leading=16, auto_space=(1, 0.06 * inch))
        if self.close_count <= 20:
            self.add_paragraph(text=f'3. 您查询期间的交易量(特别是平仓)笔数过少，只有{self.close_count}笔，诊断报告的部分数据分析可能会难以反应您真实的交易能力或实际情况。',
                               leading=16, auto_space=(1, 0.5 * inch))

        # 第一部分
        self.add_paragraph(text='第一部分   账户数据分析', font_name='SyH_N', name='SongBD', alignment=TA_CENTER,
                           font_size=20, auto_space=(1, 0.5 * inch))

        self.add_paragraph(text='1、账户数据分析', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self._add_account_overview_table()

        self.add_paragraph(text='2、账户净值分析', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)

        self.add_paragraph(text='(1)、累计净值与累计净利润', font_size=11, border_padding=4)
        self.add_image(filename='cum_net_value_cum_profit')
        self.add_paragraph(filename='cum_net_value_cum_profit', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='(2)、最大回撤', font_size=11, border_padding=4)
        self.add_image(filename='cum_pullback')
        self.add_paragraph(filename='cum_pullback', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='(3)、当日净值与波动率', font_size=11, border_padding=4)
        self.add_image(filename='net_volatility')
        self.add_paragraph(filename='net_volatility', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='3、周期盈亏分析', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4, auto_space=(1, 0.25 * inch))

        self.add_paragraph(text='(1)、每日盈亏', font_size=11, border_padding=4)
        self.add_image(filename='period_profit_daily')
        self.add_paragraph(filename='period_profit_daily', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='(2)、每周盈亏', font_size=11, border_padding=4)
        self.add_image(filename='period_profit_week')
        self.add_paragraph(filename='period_profit_week', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='(3)、每月盈亏', font_size=11, border_padding=4)
        self.add_image(filename='period_profit_month')
        self.add_paragraph(filename='period_profit_month', font_size=12, leading=18, first_line_indent=20,
                           auto_space=(1, 0.5 * inch))  # 这里的auto_space是为了间隔下面的

        # 第二部分
        self.add_paragraph(text='第二部分   交易统计分析', font_name='SyH_B', name='SongBD', alignment=TA_CENTER,
                           font_size=20, auto_space=(1, 0.5 * inch))
        self.add_paragraph(text='1、平仓盈利与亏损(按已平仓记录核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self._add_close_profit_overview_table(auto_spacer=None)
        self.add_close_overview_explain()

        self.add_paragraph(text='2、多空盈亏分析(按已平仓记录核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self.add_image(filename='pupil_profit_count_pie')
        self.add_image(filename='pupil_profit_amount_pie')

        self._add_pupil_profit_table()

        self.add_paragraph(text='3、品种盈亏分析(按已平仓记录核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self.add_image(filename='variety_profit_rank')
        self.add_paragraph(filename='variety_profit_rank', font_size=12, leading=18, first_line_indent=20)

        self.add_image(filename='variety_ljrate_rank')
        self.add_paragraph(filename='variety_ljrate_rank', font_size=12, leading=18, first_line_indent=20)
        # 单位利交比说明
        self.add_unit_profit_exchange_explain()

        self.add_paragraph(text='4、板块盈亏(交易统计核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self.add_image(filename='block_profit_month')
        self.add_paragraph(filename='block_profit_month', font_size=12, leading=18, first_line_indent=20)

        self.add_image(filename='block_profit')
        self.add_paragraph(filename='block_profit', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='5、品种成交结构(交易统计核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self.add_image(filename='variety_ex_amount_struct')
        self.add_paragraph(filename='variety_ex_amount_struct', font_size=12, leading=18, first_line_indent=20)

        self.add_paragraph(text='6、交易周期类型(按已平仓记录核算)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self.add_image(filename='exchange_period_pie')
        # 交易周期类型的表格
        self._add_exchange_type_table()

        self.add_paragraph(filename='exchange_period_pie', font_size=12, leading=18, first_line_indent=20)  # auto_space=(1, 0.5 * inch) 这里的auto_space是为了间隔下面的

        # self.add_paragraph(text='7、交易手法分析', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
        #                    text_color='#ffffff', font_size=11, border_padding=4)
        # self._add_exchange_skills()

        # 第三部分
        self.add_paragraph(text='第三部分   交易综合评价', font_name='SyH_B', name='SongBD', alignment=TA_CENTER,
                           font_size=20, auto_space=(1, 0.5 * inch))
        self.add_paragraph(text='1、账户交易评价', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)

        self.add_image(filename='evaluation_score_radar')
        self._add_evaluation_score_table()

        self.add_paragraph(text='2、交易综合分析(按已平仓记录分析)', font_name='SyH_B', name='SongBD', back_color='#81c6fc',
                           text_color='#ffffff', font_size=11, border_padding=4)
        self._add_synthetical_appraise_texts()

        # 诗句
        self.add_spacer(1, 1.3 * inch)
        self.add_paragraph(text='期市如江湖，征战永远在路上。', font_size=17, alignment=TA_CENTER, leading=22)
        if self.net_value < 0.6:
            poem = '沉舟侧畔千帆过，病树前头万木春。'
        elif 0.6 <= self.net_value < 0.8:
            poem = '采菊东篱下，悠然见南山。'
        elif 0.8 <= self.net_value < 1.2:
            poem = '路漫漫其修远兮，吾将上下而求索。'
        elif 1.2 <= self.net_value < 1.8:
            poem = '龙岂池中物，乘雷欲上天。'
        else:
            poem = '九万里风鹏正举。风休住，蓬舟吹取三山去！'
        self.add_paragraph(text=poem, font_size=17, alignment=TA_CENTER, leading=22)

        # 结束
        self.add_spacer(1, 1.3 * inch)
        self.add_paragraph(text='期市有风险，投资需谨慎，祝您投资顺利！', alignment=TA_CENTER)
        self.add_spacer(1, 1 * inch)
        self.add_paragraph(text='(报告完)', font_size=18, alignment=TA_CENTER)
        self.add_spacer(1, 0.1 * inch)
        self.add_paragraph(text='谢谢使用', font_name='SyH_B', name='SongBD', font_size=32, alignment=TA_CENTER)
        doc.build(self.story, onFirstPage=self.first_page_event, onLaterPages=self.later_page_event)
        return self.pdf_filepath.replace('\\', '/').replace(FILE_STORAGE, '')

    # 添加交易类型的数据表格
    def _add_exchange_type_table(self):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_exchange_period_pie.json'), 'r', encoding='utf8') as f:
            exchange_period = json.load(f)
        exchange_period_data = exchange_period['data']
        keys = ['name', 'v', 'tc', 'gc', 'success_rate']
        data = [
            ['交易类型', '成交额', '总次数', '盈利次数', '胜率'],
        ]
        for item in exchange_period_data:
            values = [item[k] for k in keys]
            data.append(values)
        self.story.append(Table(data, style=TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'SyH_B'),
            ('FONTNAME', (1, 0), (-1, -1), 'SyH_N'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER')
        ]), hAlign='LEFT', colWidths=[(self.PAGE_WIDTH - 2 * inch) / 5 for _ in range(3)]))

        self.story.append(Spacer(1, 0.25 * inch))  # 间隔

    def _add_account_overview_table(self):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_account_overview.json'), 'r', encoding='utf8') as f:
            overview_dict = json.load(f)
        filter_indexes = ['average_day_profit_ratio', 'last_net_value']
        overview_data = list(filter(lambda p: p['key'] not in filter_indexes,  overview_dict.get('overview', [])))
        float_keys = ['sharpe_ratio', 'calmar_ratio', 'sortino_ratio', 'last_net_value']
        percent_keys = ['annualized_profit_ratio', 'annualized_volatility', 'annualized_down_volatility',
                        'max_withdraw_ratio', 'average_risk_ratio']
        data = [[] for _ in range(math.ceil(len(overview_data) / 2))]
        cursor = -1
        for i, item in enumerate(overview_data):
            if i % 2 == 0:
                cursor += 1
            data[cursor].append(item['name'])
            value = item['value']
            if item['key'] in float_keys:
                value = round(value, 4)
            if item['key'] in percent_keys:
                value = f'{round(value * 100, 2)}%'
            data[cursor].append(value)
        # SPAN (sc, sr)
        self.story.append(Table(data, style=TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'SyH_B'),
            ('FONTNAME', (2, 0), (2, -1), 'SyH_B'),
            ('FONTNAME', (1, 0), (1, -1), 'SyH_N'),
            ('FONTNAME', (3, 0), (3, -1), 'SyH_N'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
        ]), hAlign='LEFT', colWidths=[(self.PAGE_WIDTH - 2 * inch) / 4 for _ in range(4)]))

        self.story.append(Spacer(1, 0.25 * inch))  # 间隔

    def _add_close_profit_overview_table(self, auto_spacer=(1, 0.25 * inch)):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_close_profit_overview.json'), 'r', encoding='utf8') as f:
            overview_dict = json.load(f)
        data_dict = {i['key']: i['value'] for i in overview_dict.get('overview', [])}
        success_ratio = data_dict.get('success_ratio', None)
        if success_ratio is not None:
            success_ratio = f'{round(success_ratio * 100, 2)}%'

        data = [
            ['', '盈利', '亏损', '持平'],
            ['交易次数', data_dict.get('gain_count', ''), data_dict.get('loss_count', ''), data_dict.get('level_count', '')],
            ['合计盈亏', data_dict.get('gain_amount', ''), data_dict.get('loss_amount', ''), '0'],
            ['每笔平均盈亏', data_dict.get('average_gain_amount', ''), data_dict.get('average_loss_amount', ''), '0'],
            ['总盈利', data_dict.get('total_profit', ''), '', ''],
            ['总次数', data_dict.get('total_count', ''), '', ''],
            ['胜率', success_ratio, '', ''],
            ['盈亏比', data_dict.get('gain_divisor_loss', ''), '', ''],
        ]
        # SPAN (sc, sr)
        self.story.append(Table(data, style=TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'SyH_B'),
            ('FONTNAME', (0, 0), (-1, 0), 'SyH_B'),
            ('FONTNAME', (1, 1), (-1, -1), 'SyH_N'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('SPAN', (1, 4), (3, 4)),
            ('SPAN', (1, 5), (3, 5)),
            ('SPAN', (1, 6), (3, 6)),
            ('SPAN', (1, 7), (3, 7)),
            ('ALIGN', (1, 0), (-1, -1), 'CENTER')
        ]), hAlign='LEFT', colWidths=[(self.PAGE_WIDTH - 2 * inch) / 4 for _ in range(4)]))
        if auto_spacer:
            self.add_spacer(auto_spacer[0], auto_spacer[1])  # 间隔

    def _add_pupil_profit_table(self):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_pupil_profit.json'), 'r', encoding='utf8') as f:
            pupil_data = json.load(f)

        multiple_success = pupil_data.get('multiple_success_ratio', '')
        if multiple_success:
            multiple_success = f'{round(multiple_success * 100, 2)}%'
        empty_success = pupil_data.get('empty_success_ratio', '')
        if empty_success:
            empty_success = f'{round(empty_success * 100, 2)}%'
        data = [
            ['', '多单', '', '', '空单', '', ''],
            ['', '盈利', '亏损', '持平', '盈利', '亏损', '持平'],
            ['交易次数', pupil_data.get('multiple_gain_count', ''),
             pupil_data.get('multiple_loss_count', ''),
             pupil_data.get('multiple_level_count', ''),
             pupil_data.get('empty_gain_count', ''),
             pupil_data.get('empty_loss_count', ''),
             pupil_data.get('empty_level_count', '')],
            ['合计盈利', pupil_data.get('multiple_gain_money', ''),
             pupil_data.get('multiple_loss_money', ''), '0',
             pupil_data.get('empty_gain_money', ''),
             pupil_data.get('empty_loss_money', ''), '0'],
            ['每笔平均盈利', pupil_data.get('multiple_average_gain', ''),
             pupil_data.get('multiple_average_loss', ''), '0',
             pupil_data.get('empty_average_gain', ''),
             pupil_data.get('empty_average_loss', ''), '0'],
            ['总盈利', pupil_data.get('multiple_total_profit', ''), '', '',
             pupil_data.get('empty_total_profit', ''), '', ''],
            ['总次数', pupil_data.get('multiple_total_count', ''), '', '',
             pupil_data.get('empty_total_count', ''), '', ''],
            ['胜率', multiple_success, '', '', empty_success, '', ''],
            ['盈亏比', pupil_data.get('multiple_gain_divisor_loss', ''), '', '',
             pupil_data.get('empty_gain_divisor_loss', ''), '', ''],
        ]
        # SPAN (sc, sr)
        self.story.append(Table(data, style=TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'SyH_B'),
            ('FONTNAME', (0, 0), (-1, 1), 'SyH_B'),
            ('FONTNAME', (1, 2), (-1, -1), 'SyH_N'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('SPAN', (1, 0), (3, 0)),
            ('SPAN', (4, 0), (6, 0)),
            ('SPAN', (1, 5), (3, 5)),
            ('SPAN', (1, 6), (3, 6)),
            ('SPAN', (1, 7), (3, 7)),
            ('SPAN', (1, 8), (3, 8)),
            ('SPAN', (4, 5), (6, 5)),
            ('SPAN', (4, 6), (6, 6)),
            ('SPAN', (4, 7), (6, 7)),
            ('SPAN', (4, 8), (6, 8)),
            ('ALIGN', (1, 0), (-1, -1), 'CENTER')
        ]), hAlign='LEFT', colWidths=[(self.PAGE_WIDTH - 2 * inch) / 7 for _ in range(8)]))

        self.add_spacer(1, 0.25 * inch)

    def _add_evaluation_score_table(self):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_evaluation_score.json'), 'r', encoding='utf8') as f:
            evaluation_data = json.load(f)

        # 生成表格
        data = [
            [i['name'], i['score'], i['appraise']]
            for i in evaluation_data
        ]
        self.story.append(Table(data, style=TableStyle([
            ('FONTNAME', (0, 0), (0, -1), 'SyH_B'),
            ('FONTNAME', (1, 0), (-1, -1), 'SyH_N'),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('ALIGN', (0, 0), (-1, -1), 'CENTER')
        ]), hAlign='LEFT', colWidths=[(self.PAGE_WIDTH - 2 * inch) / 3 for _ in range(3)]))

        self.add_spacer(1, 0.25 * inch)

    def _add_synthetical_appraise_texts(self):
        with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_synthetical_appraise.json'), 'r', encoding='utf8') as f:
            synthetical_data = json.load(f)
        for index, item in enumerate(synthetical_data):
            self.add_paragraph(text=f'{index + 1}、{item["name"]}', font_size=12, text_color='#b43c3c', auto_space=(1, 0.08 * inch))
            self.add_paragraph(text=item['text'], font_size=11, leading=16, first_line_indent=20)

    def _add_exchange_skills(self):
        pass  # 无该数据，本分析不可执行
        # with open(f'temp/jsonF/{self.filename_prefix}_exchange_methods.json', 'r', encoding='utf8') as f:
        #     methods_data = json.load(f)
        # if methods_data.get('description'):
        #     self.add_paragraph(text=methods_data['description'], font_size=12, leading=18, first_line_indent=20, auto_space=(1, inch))
        #     return
        # # 显示有交易手法和说明
        # for action in methods_data.get('actions', []):
        #     if action['has_action']:
        #         self.add_paragraph(text=action['name'], font_name='SyH_B', name='SongBD', font_size=12, leading=14)
        #         self.add_paragraph(text=action['text'], font_size=12, leading=16, first_line_indent=20)
        # self.add_note_explain(note=methods_data.get('note', ''), spacer_height=inch)

    def add_spacer(self, width, height):
        self.story.append(Spacer(width, height))

    def add_image(self, filename, auto_spacer=(1, 0.15 * inch)):
        image_file = self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_{filename}.png')
        self.story.append(Image(image_file, width=self.PAGE_WIDTH - 2 * inch, useDPI=True))
        if auto_spacer:
            self.add_spacer(auto_spacer[0], auto_spacer[1])

    def add_paragraph(self, filename='', text='',
                      font_name='SyH_N', name='Song', font_size=10,
                      back_color=None, text_color='#000000', border_padding=0,
                      alignment=TA_LEFT, leading=12, first_line_indent=0,
                      auto_space=(1, 0.15 * inch)):
        if filename:
            with open(self.TEMP_FOLDER.joinpath(f'{self.filename_prefix}_{filename}.txt'), 'r', encoding='utf8') as f:
                content = f.read()
        else:
            content = text
        self.story.append(Paragraph(
            content,
            ParagraphStyle(
                fontName=font_name,
                name=name,
                fontSize=font_size,
                leading=leading,
                firstLineIndent=first_line_indent,
                alignment=alignment,
                backColor=back_color,
                textColor=text_color,
                borderPadding=border_padding,
            )
        ))
        if auto_space:
            self.add_spacer(auto_space[0], auto_space[1])

    def first_page_event(self, canvas, doc):
        # 以下代码生成水印
        # canvas.translate(0.25 * PAGE_HEIGHT, 0)
        # canvas.rotate(30)
        # # canvas.setStrokeColorRGB(1, 0, 0)  # 文字轮廓色彩(似乎不起作用)
        # canvas.setFillColorRGB(0.6, 0.6, 0.6, 0.3)  # 文字填充色(默认就是黑色)
        # # canvas.setFillAlpha(0.3)
        # canvas.setFont('SyH_N', 30)
        # canvas.drawString(inch * 2.5, (PAGE_HEIGHT - inch) / 4 * 3, '瑞达期货研究院1')
        # canvas.drawRightString(PAGE_WIDTH - inch * 2.5, inch, '瑞达期货研究院2')
        # canvas.restoreState()

        canvas.saveState()
        cover_img = pathlib.Path(FILE_STORAGE).joinpath('image/source/exdoctor_cover.png')
        canvas.drawImage(cover_img, 0, 0, self.PAGE_WIDTH, self.PAGE_HEIGHT)

        # canvas.setFont('SyH_N', 7)
        # canvas.setFillColorRGB(0, 0, 0)
        # canvas.drawRightString(self.PAGE_WIDTH - inch, 0.75 * inch, "第 %d 页" % doc.page)
        # print(f'第{doc.page}页')  # 第一页运行一次

        canvas.setFont('SyH_N', 50)
        canvas.setFillColorRGB(1, 1, 0)
        canvas.drawString(2.05 * inch, 9 * inch, '交易诊断报告')

        canvas.setFont('SyH_N', 15)
        canvas.setFillColorRGB(1, 1, 1)
        canvas.drawString(self.PAGE_WIDTH / 2 - 118, 5 * inch, f'报告周期: {self.start_date.strftime("%Y-%m-%d")}到{self.end_date.strftime("%Y-%m-%d")}')

        canvas.setFont('SyH_N', 11)
        canvas.setFillColorRGB(1, 1, 1)
        canvas.drawString(self.PAGE_WIDTH / 2 - 50, 2 * inch, f'报告日期: {datetime.datetime.today().strftime("%Y-%m-%d")}')
        canvas.restoreState()
        # canvas.showPage()

    def later_page_event(self, canvas, doc):
        canvas.saveState()
        canvas.setFont('SyH_N', 7)
        canvas.drawRightString(self.PAGE_WIDTH - inch, 0.75 * inch, "第 %d 页" % (doc.page - 1))
        canvas.restoreState()
        # print(f'第{doc.page}页', doc.page)  # 第二页开始每页运行一次

    # 添加固定的单位利交比说明文字
    def add_unit_profit_exchange_explain(self):
        txt = "单位利交比=品种盈亏净额占比除以品种成交额占比，该指标反应品种单位成交额下的盈亏份额，范围为负值到正值范围，负值越大说明该品种单位成交额下的亏损额越大；正值越大说明该品种单位成交额下的盈利额越大。各品种的净盈亏先转为正值，再汇总加和作为总盈亏基数。品种盈亏净额占比=品种净盈亏除以总盈亏基数。成交额占比=品种成交额除以总成交额。"
        self.story.append(Paragraph(
            txt,
            ParagraphStyle(
                fontName='SyH_N',
                name='Song',
                fontSize=9,
                leading=12,
                firstLineIndent=0,
                alignment=TA_LEFT,
                backColor=None,
                textColor='#333333',
                borderPadding=0,
            )
        ))
        self.add_spacer(1, 0.15 * inch)

    # 添加说明文字
    def add_note_explain(self, note, spacer_height=0.15*inch):
        txt = note
        self.story.append(Paragraph(
            txt,
            ParagraphStyle(
                fontName='SyH_N',
                name='Song',
                fontSize=9,
                leading=12,
                firstLineIndent=0,
                alignment=TA_LEFT,
                backColor=None,
                textColor='#333333',
                borderPadding=0,
            )
        ))
        self.add_spacer(1, spacer_height)

    # 添加平仓统计分析表格的说明
    def add_close_overview_explain(self):
        txt = "*表中总盈利统计平仓记录的情况，不包括期间浮动收益。\n盈亏比为1时，则表示没有亏损的平仓记录。"
        self.story.append(Paragraph(
            txt,
            ParagraphStyle(
                fontName='SyH_N',
                name='Song',
                fontSize=9,
                leading=14,
                firstLineIndent=0,
                alignment=TA_LEFT,
                backColor=None,
                textColor='#333333',
                borderPadding=0,
            )
        ))
        self.add_spacer(1, 0.15 * inch)


class MixEvaluate:
    TEMP_FOLDER = pathlib.Path(FILE_STORAGE, 'sysTemp/exDoctor')
    PDF_TEMP_FOLDER = pathlib.Path(FILE_STORAGE, 'sysTemp/exDoctor/pdfReport')

    def __init__(self, fn, start: str, end: str):
        self.fn = fn
        self.start = datetime_utils.auth_yyyy_mm_dd(start, obj=True)
        self.end = datetime_utils.auth_yyyy_mm_dd(end, obj=True)
        if not self.start:
            raise HTTPException(status_code=422, detail='query参数`start`格式错误,接受yyyy-mm-dd类型')
        if not self.end:
            raise HTTPException(status_code=422, detail='query参数`end`格式错误,接受yyyy-mm-dd类型')
        self.start_integer = self.start.strftime('%Y%m%d')
        self.end_integer = self.end.strftime('%Y%m%d')

    def account_evaluate(self):
        # 查询数据库
        database = ExDoctorDatabase(fund_num=self.fn, start=self.start_integer, end=self.end_integer)
        db_data = database.query_many_data(fund=True, close=True)
        if len(db_data['fund_list']) < 1 or len(db_data['close_pos']) < 1:
            data = {'evaluation': [], 'img_file': '', 'img_url': ''}
        else:
            fund_reconciler = FundReconciler(db_data['fund_list'])
            account_overview_data = fund_reconciler.account_overview(filename_prefix=self.fn, doc=False)
            close_statistician = CloseStatistician(db_data['close_pos'])
            close_overview_data = close_statistician.close_profit_overview(filename_prefix=self.fn, doc=False)

            mix_evaluate = MixAppraise()
            # 综合评价数据
            evaluation_data = mix_evaluate.get_valuation_appraise(account_overview=account_overview_data['overview'],
                                                                  close_overview=close_overview_data['overview'])
            img_file_data = mix_evaluate.evaluation_appraise_radar(filename_prefix=self.fn, fig_size=(5.5, 3.75), evaluation_data=evaluation_data)
            data = {
                'evaluation': evaluation_data,
                'img_file': img_file_data['img_file'],
                'img_url': img_file_data['img_url']
            }
        return APIResponse.success(data=data)

    def account_synthesize(self):
        database = ExDoctorDatabase(fund_num=self.fn, start=self.start_integer, end=self.end_integer)
        db_data = database.query_many_data(fund=True, close=True)
        if len(db_data['fund_list']) < 1 or len(db_data['close_pos']) < 1:
            data = {'synthesize': []}
        else:
            synthesizer = SyntheticalAppraise(fund_data_list=db_data['fund_list'], close_data_list=db_data['close_pos'])
            data = {'synthesize': synthesizer.synthesize(filename_prefix=self.fn)}
        return APIResponse.success(data=data)

    def generate_pdf_report(self):
        # 监测是否具备生成报告的条件
        for file in report_temp_files(prefix=self.fn):
            if not file.exists():
                return APIResponse.validate_error(detail='请通过菜单查看各细节完成账户诊断再生成报告!')
        with open(self.TEMP_FOLDER.joinpath(f'{self.fn}_account_overview.json'), 'r', encoding='utf8') as fp:
            overview = json.load(fp)
        with open(self.TEMP_FOLDER.joinpath(f'{self.fn}_close_profit_overview.json'), 'r', encoding='utf8') as f2:
            close_overview = json.load(f2)
        fact_start = datetime.datetime.strptime(overview['fact_start'], '%Y-%m-%d')
        fact_end = datetime.datetime.strptime(overview['fact_end'], '%Y-%m-%d')
        pdf_handler = PdfGenerator(filename_prefix=self.fn,
                                   start_date=fact_start,
                                   end_date=fact_end,
                                   net_value=overview['cum_net_value'],
                                   close_count=close_overview['row_count'])
        filepath = pdf_handler.create_pdf_file()
        pdf_name = pathlib.Path(filepath).name
        return APIResponse.success(data={'pdf_file': STATIC_HOST + filepath, 'pdf_name': pdf_name})


mix_evaluate_api = APIRouter()


@mix_evaluate_api.get('/appraise/')  # 综合雷达能力评价
def account_evaluate(fn: str = Query(...), start: str = Query(...), end: str = Query(...)):
    return MixEvaluate(fn=fn, start=start, end=end).account_evaluate()


@mix_evaluate_api.get('/synthesize/')  # 综合文字评价
def account_synthesize(fn: str = Query(...), start: str = Query(...), end: str = Query(...)):
    return MixEvaluate(fn=fn, start=start, end=end).account_synthesize()


@mix_evaluate_api.get('/pdfReport/')  # PDF报告
def pdf_report(fn: str = Query(...), start: str = Query(...), end: str = Query(...)):
    return MixEvaluate(fn=fn, start=start, end=end).generate_pdf_report()
